using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using ZoneFiveSoftware.Common.Data.Fitness;

namespace FilteredStatistics.Common
{
    // This interface is used to add a criteria type in the plugin.  The criteria
    //  types are those that appear in the filter's list, in the left-most column
    //  (Speed, Cadence, Templates, etc.)    Even though this interface is publicly
    //  available, I do not recommend deriving from it in order to avoid static
    //  links with the Filtered Statistics DLL.  Plugins should implement all the
    //  following functions in another class that is then passed to the
    //  FilterCriteriaController's RegisterFilterCriteria method.  The controller
    //  will then create a proxy object using reflection to call the right functions
    //  in your class in order to get the right data
    public interface IFilterCriteria
    {
        // A unique id for this criteria.  This is used to get the right type of
        //  criteria when deserializing from logbook and to select the right item
        //  in the criteria list.  It is possible to cheat by having multiple
        //  classes that have the same reference id but a different behavior and
        //  data.  In those cases, you should register a placeholder criteria and
        //  use the OnSelectedInList callback to setup the right criteria wish has
        //  the same reference id.  Make sure to serialize enough information to
        //  recreate the right type when deserializing.
        Guid ReferenceId { get; }

        // Setter for the activity the following methods must refer to if required
        IActivity Activity { set; }

        // Name to display in the list of criterias
        String DisplayName { get; }

        // List of objects that implement the INamedZone interface.  These are the
        //  different criteria options as displayed in the "Item" column.  Each one
        //  of these items match a given list of valid times that are used to give
        //  the final valid times for the criteria
        List<object> NamedZones { get; }

        // Optional callback function that lets you know when this criteria has been
        //  selected in the filters list.  This is to allow to pop a dialog to refine
        //  the criteria (sub types) or to enter parameters for the criteria.  Splits
        //  criteria uses this to set the split type and possibly distance/time.
        //  Return an  object implementing IFilterCriteria that will become our criteria
        //  or null to cancel the selection.  Don't implement if you want to keep this
        //  criteria (no sub-types or configuration)
        object OnSelectedInList(object previousSelection);

        // Is this criteria only used in templates?  It might be necessary for some
        //  criterias to have 2 variants.  One that is activity dependent, the other
        //  template-only.  Time splits are an example of this.  The activity dependent
        //  version uses the activity to get the maximum time for the criteria
        //  The template version saves it's maximum time and uses it afterwards.
        //  Criterias than return true in IsTemplateOnly won't be listed in the main
        //  view's panel
        bool IsTemplateOnly { get; }

        // Is this criteria only used in the "Daily actvity" view?  It might be
        //  necessary for some criterias to have 2 variants.  One that is activity
        //  dependent, the other template-only.  Time splits are an example of this.
        //  The activity dependent version uses the activity to get the maximum time
        //  for the criteria.  The template version saves it's maximum time and uses
        //  it afterwards.  Criterias than return true in IsMainViewOnly won't be
        //  listed in the settings page
        bool IsMainViewOnly { get; }

        // Optional property that creates a template compatible version of this
        //  criteria.  The resulting criteria It can be of a different template only
        //  class or simply a clone but must be serializable. For instance, activity
        //  dependent time splits cannot be serialized but can be saved in templates
        //  by creating a different class copy that is used in templates only.  The
        //  returned object must adhere to the IFilterCriteria interface
        object TemplateCompatibleCriteria
        {
            get;
        }

        // Optional method to validate the criteria validity.  Called when the
        // registered criterias change to remove old invalid crietrias from templates.
        //  For instance when a user removes a cadence zone category, we must remove
        //  the filters that used the criteria based  on that zone.  Return true if
        //  the criteria is still valid, false otherwise.  If not provided, the
        //  criteria is always considered valid which means it doesn't depend on
        //  logbook data that can change during execution
        bool ValidateConsistency();

        // Can this criteria be serialized in a template?  Some criterias are
        //  activity dependent which makes them impossible to save in a template.
        //  An example of this is the recorded splits criteria.  We can't apply
        //  this criteria to all activities because it is dependent on the
        //  activity's recorded splits.  If this property returns true, the following
        //  functions will be used to serialize/deserialize.
        bool IsSerializable { get; }

        // Use this function to add all criteria specific data to be saved.  Do
        //  not save the IDs of the INamedZones you contain, this should be generated
        //  at run-time.  Instead, save an ID to help you re-generate the named zones.
        //  For instance, cadence criterias will save the reference ID of the
        //  IZoneCategory that matches so it can retrieve it and regenerate the named
        //  zones.  Note that this data will be saved in the logbook and that criterias
        //  that return false in this property will be discarded
        void SerializeCriteria(Stream stream);

        // A number indicating the version number of the data serialized.  Most of the
        //  time, this id should be fixed and never be changed.  It is possible though
        //  that new options need to be added so you must increase this number for
        //  forward compatibility.  The version number used during serialization will
        //  be passed to the deserialization function
        UInt16 DataVersion { get; }

        // Use this function to deserialize the data that was set in the logbook.
        //  The version number used during serialization is passed in parameter in
        //  order to allow you to use the right deserialization code.  For instance,
        //  it is possible that your current data version is 3 and users have old data
        //  saved with version 1.  Make sure you deserialize using the protocol
        //  established for version 1.  If a user tries to deserialize a version more
        //  recent than that of the plugin installed or if there is a deserialization
        //  error, return null and the data section will be skipped, removing your
        //  criteria from the template.  If everything goes well, return an object
        //  that contains the correct data.  It can be "this" or a new criteria
        //  instance if this was called on a placeholder.  Remember this function
        //  will always be called on the criteria with the right reference id as
        //  returned in your provider.
        object DeserializeCriteria(Stream stream, UInt16 version);

        // Event to trigger when the list of named zones has changed.  Causes an
        //  update and a validation of templates which use this criteria to
        //  makes sure they are valid.
        event PropertyChangedEventHandler NamedZonedListChanged;
    }
}
